/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.text; import java.awt.Font; import java.awt.Color; import java.awt.font.TextAttribute; import java.text.AttributedCharacterIterator; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.Collections; import java.util.HashSet; /** The class is a support for all classes that implement PrintCookie. * Allows creating of attributed texts. * * @author Ales Novak */ public class AttributedCharacters extends Object { /** characters to iterate */ protected char[] chars; /** font for each character */ protected Font[] fonts; /** color for each character */ protected Color[] colors; /** start indices of continuous blocks of text with the same font. */ protected int[] runStart; /** limit indices of continous ... */ protected int[] runLimit; /** current */ protected int current; /** Creates new empty AttributedCharacterIteratorImpl object. */ public AttributedCharacters() { chars = new char[10]; fonts = new Font[10]; colors = new Color[10]; runStart = new int[10]; runLimit = new int[10]; current = -1; } /** appends a character with specified Font. * @param c * @param f a Font * @param color a Color */ public void append(char c, Font f, Color color) { if (f == null) return; if (++current == chars.length) { char[] ctmp = new char[2 * chars.length]; Font[] ftmp = new Font[2 * chars.length]; Color[] cotmp = new Color[2 * chars.length]; int[] rstmp = new int[2 * chars.length]; int[] rltmp = new int[2 * chars.length]; System.arraycopy(chars, 0, ctmp, 0, chars.length); System.arraycopy(fonts, 0, ftmp, 0, chars.length); System.arraycopy(colors, 0, cotmp, 0, chars.length); System.arraycopy(runStart, 0, rstmp, 0, chars.length); System.arraycopy(runLimit, 0, rltmp, 0, chars.length); chars = ctmp; fonts = ftmp; colors = cotmp; runStart = rstmp; runLimit = rltmp; } chars[current] = c; fonts[current] = f; colors[current] = color; if (current != 0) { int prev = current - 1; if (fonts[prev].equals(f) && colors[prev].equals(color)) { runLimit[runStart[current] = runStart[prev]] = current; } else { runLimit[current] = current; runStart[current] = current; } } } /** appends a char array with a Font * @param a * @param f * @param color */ public void append(char[] a, Font f, Color color) { if (a == null || a.length == 0 || f == null || color == null) { return; } // increase buffers if (++current + a.length >= chars.length) { int size = Math.max(current + a.length, 2 * chars.length); char[] ctmp = new char[size]; Font[] ftmp = new Font[size]; Color[] cotmp = new Color[size]; int[] rstmp = new int[size]; int[] rltmp = new int[size]; System.arraycopy(chars, 0, ctmp, 0, chars.length); System.arraycopy(fonts, 0, ftmp, 0, fonts.length); System.arraycopy(colors, 0, cotmp, 0, chars.length); System.arraycopy(runStart, 0, rstmp, 0, chars.length); System.arraycopy(runLimit, 0, rltmp, 0, chars.length); chars = ctmp; fonts = ftmp; colors = cotmp; runStart = rstmp; runLimit = rltmp; } // fill buffers System.arraycopy(a, 0, chars, current, a.length); for (int i = 0; i < a.length; i++) { fonts[i + current] = f; colors[i + current] = color; } // update last member to be the runLimit for the first one in the block int prev = current - 1; int pseudo = current + a.length - 1; if (prev < 0) { // start? runLimit[0] = pseudo; } else { int replace; if (fonts[prev].equals(f) && colors[prev].equals(color)) { // increase old block runLimit[replace = runStart[pseudo] = runStart[prev]] = pseudo; } else { // new block runLimit[current] = pseudo; runStart[current] = current; runStart[pseudo] = current; replace = current; } // init items in the block - update runStart for (int i = current + 1; i < pseudo; i++) { runStart[i] = replace; } } current = pseudo; } /** * @return an AttributedCharacterIterator */ public AttributedCharacterIterator iterator() { int size = current + 1; char[] cs = new char[size]; Font[] fs = new Font[size]; Color[] colos = new Color[size]; int[] rstmp = new int[size]; int[] rltmp = new int[size]; System.arraycopy(runStart, 0, rstmp, 0, size); System.arraycopy(runLimit, 0, rltmp, 0, size); System.arraycopy(chars, 0, cs, 0, size); System.arraycopy(fonts, 0, fs, 0, size); System.arraycopy(colors, 0, colos, 0, size); AttributedCharacterIterator ret = new AttributedCharacterIteratorImpl(cs, fs, colos, rstmp, rltmp); return ret; } /** Implementation of AttributedCharacterIterator interface */ public static class AttributedCharacterIteratorImpl implements AttributedCharacterIterator { /** current position */ protected int current; /** characters to iterate */ protected char[] chars; /** font for each character */ protected Font[] fonts; /** Color for each character */ protected Color[] colors; /** start indices of continuous blocks of text with the same font. */ protected int[] runStart; /** limit indices of continous ... */ protected int[] runLimit; /** singleton */ protected Set singleton; /** Constructs new AttributedCharacterIteratorImpl object. * @param chars * @param fonts * @param rs * @param rl */ public AttributedCharacterIteratorImpl(char[] chars, Font[] fonts, Color[] colors, int[] rs, int[] rl) { this.chars = chars; this.fonts = fonts; this.colors = colors; runStart = rs; runLimit = rl; } // first implement CharacterIterator /** * Clones the object. * @return a clone */ public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { // impossible to catch it return null; } } /** * @return current char */ public char current() { if (current >= chars.length) return DONE; return chars[current]; } /** * @return first char */ public char first() { current = 0; if (current >= chars.length) return DONE; return chars[current]; } /** * @return begin index */ public int getBeginIndex() { return 0; } /** * @return end index */ public int getEndIndex() { return chars.length; } /** * @return current index */ public int getIndex() { return current; } /** * @return character at last index */ public char last() { int end = getEndIndex(); if (end == 0) { return DONE; } return chars[current = end - 1]; } /** * @return next char */ public char next() { if (current >= getEndIndex() - 1) { return DONE; } return chars[++current]; } /** * @return previous char */ public char previous() { if (current == 0) { return DONE; } return chars[--current]; } /** * @param i new index * @return char at that position */ public char setIndex(int i) { if (i < 0) throw new IllegalArgumentException(); if (i == getEndIndex()) { current = getEndIndex(); return DONE; } return chars[current = i]; } // attributes /** * @return a Set with TextAttribute.FONT */ public Set getAllAttributeKeys() { if (singleton == null) { HashSet l = new HashSet(4); l.add(TextAttribute.FONT); l.add(TextAttribute.FOREGROUND); singleton = Collections.unmodifiableSet(l); } return singleton; } /** * @param att an Attribute * @return a value for this attribute */ public Object getAttribute(AttributedCharacterIterator.Attribute att) { if (att == TextAttribute.FONT) { return fonts[getIndex()]; } else if (att == TextAttribute.FOREGROUND) { return colors[getIndex()]; } else { return null; } } /** * @return map with all attributes for current char */ public Map getAttributes() { Map m = new HashMap(1); m.put(TextAttribute.FONT, fonts[getIndex()]); m.put(TextAttribute.FOREGROUND, colors[getIndex()]); return m; } /** * @return */ public int getRunLimit() { return runLimit[runStart[getIndex()]] + 1; } /** * @param att an Attribute */ public int getRunLimit(AttributedCharacterIterator.Attribute att) { if ((att != TextAttribute.FONT) && (att != TextAttribute.FOREGROUND)) { return getEndIndex(); // undefined attribute } return getRunLimit(); } /** * @param attributes a Set of attributes */ public int getRunLimit(Set attributes) { if (attributes.contains(TextAttribute.FONT) || attributes.contains(TextAttribute.FOREGROUND) ) { return getRunLimit(); } else { return getEndIndex(); } } /** * @return run start for current char */ public int getRunStart() { return runStart[getIndex()]; } /** * @param att */ public int getRunStart(AttributedCharacterIterator.Attribute att) { if ((att != TextAttribute.FONT) && att != TextAttribute.FOREGROUND) { return 0; // undefined attribute } return getRunStart(); } /** * @param attributes a Set */ public int getRunStart(Set attributes) { if ((attributes.contains(TextAttribute.FONT)) || attributes.contains(TextAttribute.FOREGROUND) ) { return getRunStart(); } else { return 0; } } } } /* * Log * 6 src-jtulach1.5 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 5 src-jtulach1.4 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 4 src-jtulach1.3 5/12/99 Ales Novak changed comments * 3 src-jtulach1.2 4/23/99 Ales Novak color added * 2 src-jtulach1.1 4/9/99 Ian Formanek Removed debug printlns * 1 src-jtulach1.0 2/19/99 Ales Novak * $ */